#pragma once
#include <stddef.h>

#include "el_export.h"
#include "tcp_server.h"

namespace el {
	class COMM_SERVER_EXPORT ModbusTcpServer
	{
	public:
		typedef unsigned char uint_8;
		typedef unsigned short uint_16;
		typedef unsigned int uint;

		struct ModbusBuffer
		{
			uint_8 coil[10000 / 8];
			uint_8 input_coil[10000 / 8];
			uint_16 reg[10000];
			uint_16 input_reg[10000];
		};

		enum ReadCode
		{
			READ_COILS = 0x01,
			READ_INPUT_BITS = 0x02,
			READ_HOLD_REGS = 0x03,
			READ_INPUT_REGS = 0x04,
			WRITE_COIL = 0x05,
			WRITE_REG = 0x06,
			WRITE_COILS = 0x0F,
			WRITE_REGS = 0x10,
			HEART_BEAT = 0x46,
		};

		enum DataSeq
		{
			AB_CD_EF_GH = 0,
			GH_EF_CD_AB = 1,
			BA_DC_FE_HG = 2,
			HG_FE_DC_BA = 3
		};

		enum ErrorCode
		{
			OK = 0x0,
			ILLEGAL_FUNCTION = 0x1,
			ILLEGAL_ADDRESS = 0x2,
			ILLEGAL_VALUE = 0x3,
		};

		ModbusTcpServer(EventLoop *loop, SocketAddrIn &addr);
		~ModbusTcpServer();

		void start();
		void stop();
		void release();
		bool isListen();

		void setNewConnectionCallback(const NewTcpConnectCallback& callback);
		void setErrorCallback(const TcpErrorCallback& callback);
		void setStartCallback(const TcpServerStartCallback& callback);

		bool readCoils(int address, int amount, unsigned char* buffer, ErrorCode& error);
		bool readInputBits(int address, int amount, unsigned char* buffer, ErrorCode& error);
		bool readHoldingRegisters(int address, int amount, unsigned char* buffer, ErrorCode& error);
		bool readInputRegisters(int address, int amount, unsigned char* buffer, ErrorCode& error);

		bool writeCoil(int address, bool value, ErrorCode& error);
		bool writeCoils(int address, int amount, unsigned char* value, ErrorCode& error);
		bool writeRegister(int address, unsigned char* value, ErrorCode& error);
		bool writeRegisters(int address, int amount, unsigned char* value, ErrorCode& error);

		unsigned char reverseByte(unsigned char byte);
		
	private:
		void onMessage(TcpConnect* connect);


		uint_16 transEndian(uint_16 value);

	private:
		TcpServer* server_;

		DataSeq data_seq_;
		ModbusBuffer buffer_;
	};
}
